package com.ljcalc.business.components.calcs;

import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;

import com.ljcalc.business.components.Combination;
import com.ljcalc.business.components.CombinationsSet;
import com.ljcalc.business.components.HistoryResultsAnalyzer;
import com.ljcalc.business.components.LJCalcProperties;
import com.ljcalc.business.components.NumberPercentage;
import com.ljcalc.business.components.RandomPool;
import com.ljcalc.business.components.RandomPoolManager;
import com.ljcalc.business.components.SPTTHistoryResultsAnalyzer;

public class CombCalc extends AbstractCombCalc {

	protected static LinkedList<NumberPercentage> numberPercentageList = null;
	protected static LinkedList<NumberPercentage> reducedNPList = null;
	protected static long COMBINATION_SET_SIZE = 18;
	protected HistoryResultsAnalyzer analyzerInstance;
	
	public CombCalc() {
		super();
	}
	
	public boolean initialize(){
		analyzerInstance = SPTTHistoryResultsAnalyzer.getInstance(); 
		if(numberPercentageList==null){

			numberPercentageList = (LinkedList<NumberPercentage>) analyzerInstance.getLottoStat();
		}
		
		String comb_size = LJCalcProperties.getInstance().getProperty("COMBINATION_SET_SIZE");
		if(comb_size!=null){
			COMBINATION_SET_SIZE = Long.valueOf(comb_size).longValue();
		}
		
		return true;
	}
	
	/**
	 * from the list, get the n most frequent appearances out
	 * @param n
	 * @param list
	 * @return
	 */
	protected LinkedList<NumberPercentage> getMostAppearancesOutOfList(int n, LinkedList<NumberPercentage> list){
		
		LinkedList<NumberPercentage> retList = new LinkedList<NumberPercentage>(); 
			
		if(n<=0){
			return retList;
		}
		
		list = sortListWthPercentage(list);
		
		int i=0;
		Iterator<NumberPercentage> itr = list.iterator();
		while (i<n&&itr.hasNext()) {
			NumberPercentage np = (NumberPercentage) itr.next();
			retList.add(np);
			i++;
		}
		
		return retList;
	}

	protected LinkedList<NumberPercentage> sortListWthPercentage(
			LinkedList<NumberPercentage> list) {					
		Collections.sort(list, new Comparator<NumberPercentage>() {

			public int compare(NumberPercentage o1, NumberPercentage o2) {
				return (int) (o2.getPercentage()-o1.getPercentage());
			}
		});
		
		return list;
	}

	/**
	 * prefill the combinations according to the number percentage list
	 * 
	 * this is a preparation step for filling up.
	 * 
	 */
	public CombinationsSet prefilling() {		
		//initialize the combinations set
		CombinationsSet comSet = new CombinationsSet(COMBINATION_SET_SIZE,analyzerInstance.getCombType());
		reducedNPList = numberPercentageList;
		if(reducedNPList==null){
			return comSet;
		}
		
		reducedNPList = getReducedNPList(reducedNPList);

		
		//Get one Random Pool, 10^5 values, from 1 to 1000.
		RandomPool rp = RandomPoolManager.getInstance().getRandomPool(1, (int) COMBINATION_SET_SIZE);
		//get the next value from the number percentage list
		Iterator<NumberPercentage> itr = reducedNPList.iterator();
		while(itr.hasNext()){

			NumberPercentage np = itr.next();
			//calculate the number of combination samples we should fill up
			long numCom = calcNumberOfCombinations(np.getPercentage(), COMBINATION_SET_SIZE);
			//for i=0; i<number of combination samples; i++
			for(int i=0;i<numCom;i++){
				if(rp.size()==0){
					rp =  RandomPoolManager.getInstance().getRandomPool(1, (int) COMBINATION_SET_SIZE);
				}
				//get the next value from Random Pool
				long n = rp.getNextRandomValue();
				//get the combination out combination[random_value]
				//use combination[random_value] insert numberPercentageItem.getnumber
				//if insert returns false, i = i-1;
				if(!comSet.get((int) (n-1)).insertNumber(np.getNum())){
					i = i-1;
				}

			}
		}
		return comSet;
	} 

	protected LinkedList<NumberPercentage> getReducedNPList(
			LinkedList<NumberPercentage> reducedNPList2) {
		//Get the top n numbers out according to the most appearance
		String most = LJCalcProperties.getInstance().getProperty("Number_Of_Most_Appearance");
		if(most!=null){
			long lmost = Long.valueOf(most).longValue();
			reducedNPList2 = getMostAppearancesOutOfList((int) lmost,reducedNPList2);
		}
		return reducedNPList2;
	}

	/**
	 * fill up the combinations with the left numbers till they are full.
	 */
	public CombinationsSet fillUp(CombinationsSet combset) {
		//we should know what numbers are left to be filled
		LinkedList<Long> numberList = new LinkedList<Long>();
		Iterator<NumberPercentage> itr = reducedNPList.iterator();
		while (itr.hasNext()) {
			NumberPercentage numberPercentage = (NumberPercentage) itr.next();
			numberList.add(new Long(numberPercentage.getNum()));
		}
		//1 is lotto min, 35 is lotto max		
		Iterator<Combination> combItr = combset.iterator();
		while (combItr.hasNext()) {
			Combination comb = (Combination) combItr.next();
			while(!comb.isFull()){
				comb.insertNumber(RandomPoolManager.getInstance().getRandomPool(1, analyzerInstance.getMaxNumber(), numberList).getNextRandomValue());
			}			
		}
		
		return combset;
	}
	
	protected long calcNumberOfCombinations(long percentage, long totalNumberOfSamples) {
		return percentage*totalNumberOfSamples/100;
	}



}
